/**
 * 视频流拍照 iOS>=11 Android>=5
 * @class liveCamera
 * @see {@link https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/video video documents}
 * @see {@link https://developer.mozilla.org/zh-CN/docs/Web/API/MediaDevices/getUserMedia getUserMedia documents}
 */
class liveCamera {
  /**
   * @param {dom} video video dom
   * @method canUse 判断兼容
   * @method openCamera 调起相机
   * @method closeCamera 关闭相机
   * @method takePhoto 获取当前帧图像
   */
  constructor(video) {
    this.video = video // 拿到video dom
    // this.width = this.video.style.width.replace(/[^\d]/g, "") // 拿到video宽度
    // this.height = this.video.style.height.replace(/[^\d]/g, "") // 拿到video高度
    this.width = this.video.videoWidth // 拿到video宽度
    this.height = this.video.videoHeight // 拿到video高度
    this.constraints = {
      audio: false,
      video: {
        width: {
          ideal: 1080,
        },
        // facingMode: {
        //   exact: "environment", //后置摄像头
        // },
        facingMode: "user", //前置摄像头
      },
    } // 媒体对象入参
    this.mediaStream = null // 当前视频流
  }

  /**
   * 判断兼容
   * @returns {boolean} 是否支持视频流拍照
   */
  canUse = () => {
    if (
      !!(
        navigator?.mediaDevices?.getUserMedia &&
        document.createElement("canvas")?.getContext("2d")
      )
    )
      return true
    // 老的浏览器可能根本没有实现 mediaDevices，所以我们可以先设置一个空的对象
    if (navigator.mediaDevices === undefined) {
      navigator.mediaDevices = {}
    }
    // 一些浏览器部分支持 mediaDevices。我们不能直接给对象设置 getUserMedia
    // 因为这样可能会覆盖已有的属性。这里我们只会在没有getUserMedia属性的时候添加它。
    if (navigator.mediaDevices.getUserMedia === undefined) {
      // 首先，如果有getUserMedia的话，就获得它
      let getUserMedia =
        navigator.webkitGetUserMedia ||
        navigator.mozGetUserMedia ||
        navigator.getUserMedia
      console.log("getUserMedia------", getUserMedia)
      if (getUserMedia === undefined) return false
      // 一些浏览器根本没实现它 - 那么就返回一个error到promise的reject来保持一个统一的接口
      // 否则，为老的navigator.getUserMedia方法包裹一个Promise
      navigator.mediaDevices.getUserMedia = new Promise(function (
        resolve,
        reject
      ) {
        getUserMedia.call(navigator, constraints, resolve, reject)
      })
      return true
    }
  }

  /**
   * 调起相机
   * @return {string} msg 成功/失败消息
   */
  openCamera = () =>
    new Promise(async (resolve, reject) => {
      if (!this.mediaStream) {
        navigator.mediaDevices
          .getUserMedia(this.constraints)
          .then(mediaStream => {
            // 获取当前视频流
            this.mediaStream = mediaStream
            if ("srcObject" in this.video) {
              this.video.srcObject = this.mediaStream
              this.video.setAttribute("playsinline", true)
              this.video.play()
            } else {
              // 防止在新的浏览器里使用它，应为它已经不再支持了
              this.video.src = window.URL.createObjectURL(this.mediaStream)
              this.video.setAttribute("playsinline", true)
              this.video.play()
            }
            this.video.onloadedmetadata = e => {
              console.log("视频加载完毕---", e)
              this.video.play()
              resolve("camera-open ok")
            }
          })
          .catch(err => {
            console.log("错误:", err)
            reject(err.name + ": " + err.message)
          })
      } else {
        reject("camera already")
      }
    })

  /**
   * 关闭相机
   * @return {string} msg 成功/失败消息
   */
  closeCamera = () =>
    new Promise((resolve, reject) => {
      if (this.mediaStream) {
        this.video.srcObject = null // 清除video资源
        this.video.pause() // video停止播放
        this.mediaStream.getTracks().forEach(el => el.stop()) // 关闭所有流媒体轨道，关闭相机
        this.mediaStream = null // 清除视频流对象
        resolve("camera-close ok")
      } else {
        reject("camera unready")
      }
    })

  /**
   * 获取当前帧图像
   * @return {string} img2B64 图片 (image/jpeg)
   */
  takePhoto = () =>
    new Promise((resolve, reject) => {
      if (this.mediaStream) {
        const canvas = document.createElement("canvas") // 创建canvas dom
        canvas.width = this.width // 设置canvas宽度
        canvas.height = this.height // 设置canvas高度
        document.body.append(canvas) // 将canvas插入文档
        canvas
          .getContext("2d")
          .drawImage(this.video, 0, 0, this.width, this.height) // 绘制图像
        const img2B64 = canvas.toDataURL("image/jpeg", 5) // 将图像转为base64
        resolve(img2B64)
        canvas.remove() // 移除canvas dom
      } else {
        reject("camera unready")
      }
    })
}
